/* ----------------------------------------------------------------------------------------------------------------
 * InputManager
 * ----------------------------------------------------------------------------------------------------------------
 */
package pure.engine.system
{
	import flash.events.KeyboardEvent;

	use namespace ns_despair;
	
	/**
	 * @internal
	 * 
	 * 按键管理器
	 * 
	 * @param Pure
	 * 
	 * ＃更新优先级最高
	 * 
	 * ［-1:justRelease］［0:None］［1:Press］［2:justPress］
	 */
public class InputManager implements IFrameObject
{
	public function InputManager() 
	{
		_lookup = new Object();
		_map = new Vector.<Object>(_total, true);
		_addAllKeys();
		
		SystemManager.m_stage.addEventListener(KeyboardEvent.KEY_DOWN, ____onKeyDown);
		SystemManager.m_stage.addEventListener(KeyboardEvent.KEY_UP, ____onKeyUp);
		
		ProcessManager.instance.addFrameObject(this, 10);
	}
	
	
	internal var _lookup:Object;
	internal var _map:Vector.<Object>;
	internal const _total:uint = 91;  // 256
	
	public var ESC:Boolean;
	public var F1:Boolean;
	public var F2:Boolean;
	public var F3:Boolean;
	public var F4:Boolean;
	public var F5:Boolean;
	public var F6:Boolean;
	public var F7:Boolean;
	public var F8:Boolean;
	public var F9:Boolean;
	public var F10:Boolean;
	public var F11:Boolean;
	public var F12:Boolean;
	public var ONE:Boolean;
	public var TWO:Boolean;
	public var THREE:Boolean;
	public var FOUR:Boolean;
	public var FIVE:Boolean;
	public var SIX:Boolean;
	public var SEVEN:Boolean;
	public var EIGHT:Boolean;
	public var NINE:Boolean;
	public var ZERO:Boolean;
	public var NUMPADONE:Boolean;
	public var NUMPADTWO:Boolean;
	public var NUMPADTHREE:Boolean;
	public var NUMPADFOUR:Boolean;
	public var NUMPADFIVE:Boolean;
	public var NUMPADSIX:Boolean;
	public var NUMPADSEVEN:Boolean;
	public var NUMPADEIGHT:Boolean;
	public var NUMPADNINE:Boolean;
	public var NUMPADZERO:Boolean;
	public var PAGEUP:Boolean;
	public var PAGEDOWN:Boolean;
	public var HOME:Boolean;
	public var END:Boolean;
	public var INSERT:Boolean;
	public var MINUS:Boolean;    // 减号
	public var PLUS:Boolean;    // 加号
	public var DELETE:Boolean;
	public var BACKSPACE:Boolean;    // 回车
	public var TAB:Boolean;
	public var Q:Boolean;
	public var W:Boolean;
	public var E:Boolean;
	public var R:Boolean;
	public var T:Boolean;
	public var Y:Boolean;
	public var U:Boolean;
	public var I:Boolean;
	public var O:Boolean;
	public var P:Boolean;
	public var LBRACKET:Boolean;    // [
	public var RBRACKET:Boolean;    // ]
	public var BACKSLASH:Boolean;    // "\"
	public var CAPSLOCK:Boolean;
	public var A:Boolean;
	public var S:Boolean;
	public var D:Boolean;
	public var F:Boolean;
	public var G:Boolean;
	public var H:Boolean;
	public var J:Boolean;
	public var K:Boolean;
	public var L:Boolean;
	public var SEMICOLON:Boolean;    // ;
	public var QUOTE:Boolean;    // ""
	public var ENTER:Boolean;
	public var SHIFT:Boolean;
	public var Z:Boolean;
	public var X:Boolean;
	public var C:Boolean;
	public var V:Boolean;
	public var B:Boolean;
	public var N:Boolean;
	public var M:Boolean;
	public var COMMA:Boolean;    // ,
	public var PERIOD:Boolean;    // .
	public var SLASH:Boolean;    // /
	public var CONTROL:Boolean;
	public var ALT:Boolean;
	public var SPACE:Boolean;
	public var UP:Boolean;
	public var DOWN:Boolean;
	public var LEFT:Boolean;
	public var RIGHT:Boolean;
	
	
	
	
	// 是否按下指定键
	public function pressed(key:String):Boolean
	{
		return this[key]; 
	}

	
	// 是否刚按下指定键
	public function justPressed(key:String):Boolean 
	{ 
		return _map[_lookup[key]].current == 2;
	}

	
	// 是否刚弹起指定键
	public function justReleased(key:String):Boolean 
	{ 
		return _map[_lookup[key]].current == -1;
	}

	
	// 是否按下任何键
	public function any():Boolean
	{
		var i:uint = 0;
		while (i < _total) 
		{
			var o:Object = _map[i++];
			
			if ((o != null) && (o.current > 0))
			{
				return true;
			}
		}
		return false;
	}
	
	
	/**
	 * 重置
	 */
	public function reset():void
	{
		var i:uint = 0;
		while (i < _total) 
		{
			var o:Object = _map[i++];
			if(o == null) continue;
			this[o.name] = false;
			o.current = 0;
			o.nm = 0;
		}
	}

	/**
	 * If any keys are not "released" (0),
	 * this function will return an array indicating
	 * which keys are pressed and what state they are in.
	 * 
	 * @return	An array of key state data.  Null if there is no data.
	 */
	public function record():Array
	{
		var data:Array = null;
		var i:uint = 0;
		while(i < _total)
		{
			var o:Object = _map[i++];
			if((o == null) || (o.current == 0))
				continue;
			if(data == null)
				data = new Array();
			data.push({code:i-1,value:o.current});
		}
		return data;
	}
	
	/**
	 * Part of the keystroke recording system.
	 * Takes data about key presses and sets it into array.
	 * 
	 * @param	Record	Array of data about key states.
	 */
	public function playback(Record:Array):void
	{
		var i:uint = 0;
		var l:uint = Record.length;
		var o:Object;
		var o2:Object;
		while(i < l)
		{
			o = Record[i++];
			o2 = _map[o.code];
			o2.current = o.value;
			if (o.value > 0)
			{
				this[o2.name] = true;
			}
		}
	}
	
	
	// 帧更新
	
	// [Process] 
	// ① （本帧）更新上一帧按键状态
	// ② （次帧）根据上一帧按键状态，判断当前按键状态
	// [Hint] - [-1] justRelease，[0] Release，[1] Press，[2] justPress
	public function onFrame(elapsedT:Number ):void 
	{
		var i:uint = 0;
		while (i < _total) 
		{
			var o:Object = _map[i++];
			if (o == null) continue;
			
			// justRelease
			if ((o.last == -1) && (o.current == -1))
			{
				o.current = 0;
			}
			
			// justPress
			else if ((o.last == 2) && (o.current == 2))
			{
				o.current = 1;
			}
			
			// 更新上一帧按键状态
			o.last = o.current;
		}
	}
	

	
	
	/* ----------------------------------------------------------------------------------------------------------------
	 * ★★★★★★★★★★★★★★★★★★★★★  private  ★★★★★★★★★★★★★★★★★★★★★
	 * ----------------------------------------------------------------------------------------------------------------
	 */
	


	
	final private function _addAllKeys():void 
	{
		// 字母A-Z
		var i:uint = 65;
		while (i <= 90) 
		{
			_addKey(String.fromCharCode(i),i++);
		}
		
		// 数字
		i = 48;
		_addKey("ZERO",i++);
		_addKey("ONE",i++);
		_addKey("TWO",i++);
		_addKey("THREE",i++);
		_addKey("FOUR",i++);
		_addKey("FIVE",i++);
		_addKey("SIX",i++);
		_addKey("SEVEN",i++);
		_addKey("EIGHT",i++);
		_addKey("NINE", i++);
		
		//i = 96;
		//_addKey("NUMPADZERO",i++);
		//_addKey("NUMPADONE",i++);
		//_addKey("NUMPADTWO",i++);
		//_addKey("NUMPADTHREE",i++);
		//_addKey("NUMPADFOUR",i++);
		//_addKey("NUMPADFIVE",i++);
		//_addKey("NUMPADSIX",i++);
		//_addKey("NUMPADSEVEN",i++);
		//_addKey("NUMPADEIGHT",i++);
		//_addKey("NUMPADNINE",i++);
		//_addKey("PAGEUP", 33);
		//_addKey("PAGEDOWN", 34);
		//_addKey("HOME", 36);
		//_addKey("END", 35);
		//_addKey("INSERT", 45);
		
		// F1~F12
		//i = 1;
		//while(i <= 12) _addKey("F"+i,111+(i++));
		
		//SPECIAL KEYS + PUNCTUATION
		_addKey("ESC",27);
		//_addKey("MINUS",189);
		//_addKey("PLUS",187);
		//_addKey("DELETE",46);
		//_addKey("BACKSPACE",8);
		//_addKey("LBRACKET",219);
		//_addKey("RBRACKET",221);
		//_addKey("BACKSLASH",220);
		//_addKey("CAPSLOCK",20);
		//_addKey("SEMICOLON",186);
		//_addKey("QUOTE",222);
		//_addKey("ENTER",13);
		//_addKey("SHIFT",16);
		//_addKey("COMMA",188);
		//_addKey("PERIOD",190);
		//_addKey("SLASH",191);
		_addKey("CONTROL",17);
		_addKey("ALT",18);
		_addKey("SPACE",32);
		_addKey("UP",38);
		_addKey("DOWN",40);
		_addKey("LEFT",37);
		_addKey("RIGHT",39);
		//_addKey("TAB", 9);
	}
	
	
	// 加入按键
	final private function _addKey(keyName:String, keyCode:uint):void
	{
		_lookup[keyName] = keyCode;
		_map[keyCode] = { name: keyName, current: 0, last: 0 };
	}

	
	// [Event]
	// 键下
	
	// [Hint] - [-1] justRelease，[0] Release，[1] Press，[2] justPress
	final private function ____onKeyDown(e:KeyboardEvent):void
	{
		e.updateAfterEvent();
		
		var object:Object = _map[e.keyCode];
		if (object == null) return;
		
		// current > 0:按住
		if (object.current > 0) {
			object.current = 1;
		}
		
		// current <= 0:未按
		else {
			object.current = 2;
		}
		this[object.name] = true;
	}

	
	// [Event]
	// 键下
	final private function ____onKeyUp(e:KeyboardEvent):void 
	{
		e.updateAfterEvent();
		
		var object:Object = _map[e.keyCode];
		if(object == null) return;
		if (object.current > 0)
		{
			object.current = -1;
		}
		
		else 
		{
			object.current = 0;
		}
		this[object.name] = false;
	}

}
}
